"""
设备故障检测和维护管理模块
Device Fault Detection and Maintenance Management Module
"""

import random
import json
from datetime import datetime, timedelta
from dataclasses import dataclass
from typing import List, Dict, Any, Optional
import numpy as np

@dataclass
class Device:
    """设备信息"""
    device_id: str
    device_name: str
    device_type: str  # sensor, actuator, controller
    location: str
    install_date: datetime
    last_maintenance: datetime
    status: str  # online, offline, warning, error
    health_score: float  # 0-100
    operating_hours: int
    maintenance_interval: int  # days

@dataclass
class FaultEvent:
    """故障事件"""
    event_id: str
    device_id: str
    fault_type: str
    severity: str  # low, medium, high, critical
    description: str
    timestamp: datetime
    resolved: bool
    resolution_time: Optional[datetime]

@dataclass
class MaintenanceTask:
    """维护任务"""
    task_id: str
    device_id: str
    task_type: str  # preventive, corrective, emergency
    description: str
    scheduled_date: datetime
    priority: str  # low, medium, high, urgent
    estimated_duration: int  # minutes
    required_parts: List[str]
    assigned_technician: str
    status: str  # pending, in_progress, completed, cancelled

class DeviceMonitoringSystem:
    """设备监控系统"""
    
    def __init__(self):
        self.devices = self._initialize_devices()
        self.fault_history = []
        self.maintenance_tasks = []
        self.fault_patterns = self._load_fault_patterns()
        
    def _initialize_devices(self) -> List[Device]:
        """初始化设备列表"""
        devices = [
            Device("SENSOR_001", "土壤湿度传感器1", "sensor", "区域A", 
                  datetime.now() - timedelta(days=180), 
                  datetime.now() - timedelta(days=30), 
                  "online", 95.2, 4320, 90),
            Device("SENSOR_002", "土壤温度传感器1", "sensor", "区域A", 
                  datetime.now() - timedelta(days=165), 
                  datetime.now() - timedelta(days=45), 
                  "online", 88.7, 3960, 90),
            Device("SENSOR_003", "空气温湿度传感器1", "sensor", "区域A", 
                  datetime.now() - timedelta(days=200), 
                  datetime.now() - timedelta(days=60), 
                  "warning", 75.3, 4800, 60),
            Device("SENSOR_004", "光照传感器1", "sensor", "区域B", 
                  datetime.now() - timedelta(days=120), 
                  datetime.now() - timedelta(days=20), 
                  "online", 92.1, 2880, 120),
            Device("ACTUATOR_001", "灌溉阀门1", "actuator", "区域A", 
                  datetime.now() - timedelta(days=240), 
                  datetime.now() - timedelta(days=15), 
                  "online", 89.5, 5760, 45),
            Device("ACTUATOR_002", "灌溉阀门2", "actuator", "区域B", 
                  datetime.now() - timedelta(days=220), 
                  datetime.now() - timedelta(days=35), 
                  "online", 91.8, 5280, 45),
            Device("ACTUATOR_003", "水泵1", "actuator", "泵房", 
                  datetime.now() - timedelta(days=300), 
                  datetime.now() - timedelta(days=7), 
                  "online", 84.2, 7200, 30),
            Device("CONTROLLER_001", "边缘控制器1", "controller", "控制室", 
                  datetime.now() - timedelta(days=365), 
                  datetime.now() - timedelta(days=90), 
                  "online", 96.7, 8760, 180),
        ]
        return devices
    
    def _load_fault_patterns(self) -> Dict:
        """加载故障模式"""
        return {
            "sensor": {
                "drift": {"probability": 0.15, "severity": "medium", "description": "传感器读数漂移"},
                "calibration": {"probability": 0.10, "severity": "low", "description": "需要重新校准"},
                "connection": {"probability": 0.08, "severity": "high", "description": "连接故障"},
                "power": {"probability": 0.05, "severity": "critical", "description": "电源故障"},
                "aging": {"probability": 0.12, "severity": "medium", "description": "设备老化"}
            },
            "actuator": {
                "stuck": {"probability": 0.12, "severity": "high", "description": "执行器卡死"},
                "leak": {"probability": 0.10, "severity": "medium", "description": "阀门泄漏"},
                "motor": {"probability": 0.08, "severity": "high", "description": "电机故障"},
                "calibration": {"probability": 0.15, "severity": "low", "description": "需要校准"},
                "wear": {"probability": 0.18, "severity": "medium", "description": "磨损严重"}
            },
            "controller": {
                "software": {"probability": 0.05, "severity": "medium", "description": "软件故障"},
                "memory": {"probability": 0.03, "severity": "high", "description": "内存不足"},
                "storage": {"probability": 0.04, "severity": "medium", "description": "存储故障"},
                "network": {"probability": 0.07, "severity": "high", "description": "网络连接问题"},
                "overheating": {"probability": 0.06, "severity": "high", "description": "过热保护"}
            }
        }
    
    def detect_faults(self) -> List[FaultEvent]:
        """检测设备故障"""
        new_faults = []
        
        for device in self.devices:
            # 基于设备状态和运行时间计算故障概率
            base_fault_prob = 0.01  # 基础故障概率
            
            # 设备老化因子
            age_days = (datetime.now() - device.install_date).days
            aging_factor = 1 + (age_days / 365) * 0.5  # 每年增加50%故障概率
            
            # 健康评分因子
            health_factor = (100 - device.health_score) / 100 + 1
            
            # 维护间隔因子
            days_since_maintenance = (datetime.now() - device.last_maintenance).days
            maintenance_factor = max(1, days_since_maintenance / device.maintenance_interval)
            
            # 运行时间因子
            hours_factor = 1 + (device.operating_hours / 8760) * 0.3  # 每年运行增加30%
            
            # 综合故障概率
            total_fault_prob = base_fault_prob * aging_factor * health_factor * maintenance_factor * hours_factor
            
            # 检查是否发生故障
            if random.random() < total_fault_prob:
                fault_type = self._generate_fault_type(device.device_type)
                fault_info = self.fault_patterns[device.device_type][fault_type]
                
                fault = FaultEvent(
                    event_id=f"FAULT_{len(self.fault_history)+1:04d}",
                    device_id=device.device_id,
                    fault_type=fault_type,
                    severity=fault_info["severity"],
                    description=f"{device.device_name}: {fault_info['description']}",
                    timestamp=datetime.now(),
                    resolved=False,
                    resolution_time=None
                )
                
                new_faults.append(fault)
                self.fault_history.append(fault)
                
                # 更新设备状态
                if fault.severity in ["high", "critical"]:
                    device.status = "error"
                elif fault.severity == "medium":
                    device.status = "warning"
                
                # 降低设备健康评分
                health_reduction = {"low": 2, "medium": 5, "high": 10, "critical": 20}
                device.health_score = max(0, device.health_score - health_reduction[fault.severity])
        
        return new_faults
    
    def _generate_fault_type(self, device_type: str) -> str:
        """根据概率生成故障类型"""
        fault_types = list(self.fault_patterns[device_type].keys())
        probabilities = [self.fault_patterns[device_type][ft]["probability"] 
                        for ft in fault_types]
        
        return np.random.choice(fault_types, p=np.array(probabilities)/sum(probabilities))
    
    def generate_maintenance_schedule(self) -> List[MaintenanceTask]:
        """生成维护计划"""
        new_tasks = []
        
        for device in self.devices:
            # 检查是否需要预防性维护
            days_since_maintenance = (datetime.now() - device.last_maintenance).days
            
            if days_since_maintenance >= device.maintenance_interval * 0.9:  # 90%维护间隔
                task = MaintenanceTask(
                    task_id=f"MAINT_{len(self.maintenance_tasks)+1:04d}",
                    device_id=device.device_id,
                    task_type="preventive",
                    description=f"定期维护 - {device.device_name}",
                    scheduled_date=datetime.now() + timedelta(days=7),
                    priority="medium",
                    estimated_duration=self._get_maintenance_duration(device.device_type),
                    required_parts=self._get_required_parts(device.device_type),
                    assigned_technician="技术员A",
                    status="pending"
                )
                new_tasks.append(task)
                self.maintenance_tasks.append(task)
            
            # 检查是否需要紧急维修
            if device.status == "error":
                unresolved_faults = [f for f in self.fault_history 
                                   if f.device_id == device.device_id and not f.resolved]
                for fault in unresolved_faults:
                    if fault.severity in ["high", "critical"]:
                        task = MaintenanceTask(
                            task_id=f"REPAIR_{len(self.maintenance_tasks)+1:04d}",
                            device_id=device.device_id,
                            task_type="emergency",
                            description=f"紧急维修 - {fault.description}",
                            scheduled_date=datetime.now() + timedelta(hours=2),
                            priority="urgent" if fault.severity == "critical" else "high",
                            estimated_duration=self._get_repair_duration(fault.fault_type),
                            required_parts=self._get_repair_parts(fault.fault_type),
                            assigned_technician="技术员B",
                            status="pending"
                        )
                        new_tasks.append(task)
                        self.maintenance_tasks.append(task)
        
        return new_tasks
    
    def _get_maintenance_duration(self, device_type: str) -> int:
        """获取维护持续时间"""
        durations = {
            "sensor": 30,
            "actuator": 60,
            "controller": 120
        }
        return durations.get(device_type, 60)
    
    def _get_required_parts(self, device_type: str) -> List[str]:
        """获取所需配件"""
        parts = {
            "sensor": ["校准工具", "清洁剂", "密封圈"],
            "actuator": ["润滑油", "密封件", "滤网"],
            "controller": ["备用电池", "散热硅胶", "内存条"]
        }
        return parts.get(device_type, [])
    
    def _get_repair_duration(self, fault_type: str) -> int:
        """获取维修持续时间"""
        durations = {
            "drift": 20,
            "calibration": 30,
            "connection": 45,
            "power": 90,
            "aging": 120,
            "stuck": 60,
            "leak": 75,
            "motor": 120,
            "wear": 90,
            "software": 45,
            "memory": 60,
            "storage": 90,
            "network": 30,
            "overheating": 60
        }
        return durations.get(fault_type, 60)
    
    def _get_repair_parts(self, fault_type: str) -> List[str]:
        """获取维修所需配件"""
        parts = {
            "drift": ["校准标准", "调节工具"],
            "calibration": ["校准设备", "标准溶液"],
            "connection": ["连接线", "接头"],
            "power": ["电源模块", "保险丝"],
            "aging": ["传感器元件", "外壳"],
            "stuck": ["润滑剂", "密封圈"],
            "leak": ["密封件", "垫片"],
            "motor": ["电机", "碳刷"],
            "wear": ["磨损件", "轴承"],
            "software": ["软件更新包"],
            "memory": ["内存模块"],
            "storage": ["存储设备"],
            "network": ["网络模块", "天线"],
            "overheating": ["散热器", "风扇"]
        }
        return parts.get(fault_type, [])
    
    def get_device_health_report(self) -> Dict[str, Any]:
        """获取设备健康报告"""
        total_devices = len(self.devices)
        online_devices = sum(1 for d in self.devices if d.status == "online")
        warning_devices = sum(1 for d in self.devices if d.status == "warning")
        error_devices = sum(1 for d in self.devices if d.status == "error")
        
        avg_health_score = sum(d.health_score for d in self.devices) / total_devices
        
        # 按设备类型统计
        device_type_stats = {}
        for device_type in ["sensor", "actuator", "controller"]:
            devices_of_type = [d for d in self.devices if d.device_type == device_type]
            if devices_of_type:
                device_type_stats[device_type] = {
                    "count": len(devices_of_type),
                    "avg_health": sum(d.health_score for d in devices_of_type) / len(devices_of_type),
                    "online": sum(1 for d in devices_of_type if d.status == "online"),
                    "issues": sum(1 for d in devices_of_type if d.status in ["warning", "error"])
                }
        
        # 最近故障统计
        recent_faults = [f for f in self.fault_history 
                        if f.timestamp > datetime.now() - timedelta(days=7)]
        
        # 待处理维护任务
        pending_tasks = [t for t in self.maintenance_tasks if t.status == "pending"]
        urgent_tasks = [t for t in pending_tasks if t.priority == "urgent"]
        
        return {
            "overview": {
                "total_devices": total_devices,
                "online": online_devices,
                "warning": warning_devices,
                "error": error_devices,
                "avg_health_score": avg_health_score,
                "system_availability": (online_devices / total_devices) * 100
            },
            "device_types": device_type_stats,
            "recent_activity": {
                "faults_last_7_days": len(recent_faults),
                "pending_maintenance": len(pending_tasks),
                "urgent_tasks": len(urgent_tasks)
            },
            "recommendations": self._generate_health_recommendations()
        }
    
    def _generate_health_recommendations(self) -> List[str]:
        """生成健康状况建议"""
        recommendations = []
        
        # 检查低健康评分设备
        low_health_devices = [d for d in self.devices if d.health_score < 70]
        if low_health_devices:
            recommendations.append(f"有{len(low_health_devices)}台设备健康评分低于70%，建议优先维护")
        
        # 检查故障设备
        error_devices = [d for d in self.devices if d.status == "error"]
        if error_devices:
            recommendations.append(f"有{len(error_devices)}台设备处于故障状态，需要立即处理")
        
        # 检查过期维护
        overdue_devices = []
        for device in self.devices:
            days_since_maintenance = (datetime.now() - device.last_maintenance).days
            if days_since_maintenance > device.maintenance_interval:
                overdue_devices.append(device)
        
        if overdue_devices:
            recommendations.append(f"有{len(overdue_devices)}台设备维护过期，建议安排维护")
        
        # 检查设备老化
        old_devices = [d for d in self.devices 
                      if (datetime.now() - d.install_date).days > 1095]  # 3年以上
        if old_devices:
            recommendations.append(f"有{len(old_devices)}台设备使用超过3年，建议考虑更换")
        
        if not recommendations:
            recommendations.append("所有设备运行良好，请继续保持定期维护")
        
        return recommendations
    
    def simulate_maintenance_completion(self, task_id: str):
        """模拟完成维护任务"""
        for task in self.maintenance_tasks:
            if task.task_id == task_id:
                task.status = "completed"
                
                # 更新设备状态
                device = next((d for d in self.devices if d.device_id == task.device_id), None)
                if device:
                    device.last_maintenance = datetime.now()
                    device.health_score = min(100, device.health_score + 10)  # 维护后健康评分提升
                    if device.status in ["warning", "error"]:
                        device.status = "online"  # 维护后恢复正常
                
                # 标记相关故障为已解决
                for fault in self.fault_history:
                    if fault.device_id == task.device_id and not fault.resolved:
                        fault.resolved = True
                        fault.resolution_time = datetime.now()
                
                break
    
    def get_maintenance_calendar(self, days_ahead: int = 30) -> List[Dict]:
        """获取维护日历"""
        calendar_events = []
        end_date = datetime.now() + timedelta(days=days_ahead)
        
        # 已安排的维护任务
        for task in self.maintenance_tasks:
            if task.status == "pending" and task.scheduled_date <= end_date:
                calendar_events.append({
                    "date": task.scheduled_date.strftime("%Y-%m-%d"),
                    "type": "scheduled_maintenance",
                    "task_id": task.task_id,
                    "device": next((d.device_name for d in self.devices 
                                  if d.device_id == task.device_id), "未知设备"),
                    "description": task.description,
                    "priority": task.priority,
                    "duration": task.estimated_duration
                })
        
        # 预测的维护需求
        for device in self.devices:
            days_since_maintenance = (datetime.now() - device.last_maintenance).days
            days_until_maintenance = device.maintenance_interval - days_since_maintenance
            
            if 0 < days_until_maintenance <= days_ahead:
                maintenance_date = datetime.now() + timedelta(days=days_until_maintenance)
                calendar_events.append({
                    "date": maintenance_date.strftime("%Y-%m-%d"),
                    "type": "predicted_maintenance",
                    "device": device.device_name,
                    "description": f"预计维护时间到期",
                    "priority": "medium",
                    "duration": self._get_maintenance_duration(device.device_type)
                })
        
        # 按日期排序
        calendar_events.sort(key=lambda x: x["date"])
        
        return calendar_events